[#ftl]
[@define "agile._Container" 
 "_Container,_ContainerMoveCoordinatorMixin,_ContainerSelectorMixin,_Contained,_DataStore" 
 "_Container=dijit/_Container,move=dojo/dnd/move,_ContainerMoveCoordinatorMixin=agile._ContainerMoveCoordinatorMixin,_ContainerSelectorMixin=agile._ContainerSelectorMixin,_Contained=agile._Contained,_DataStore=agile._DataStore"]
	isContainer:true,sortAxis:"xy",accept:null,_children:null,hasSelector:false,lastChildIndex:0,childMinZIndex:1,childMaxZIndex:1,_singleSelect:true
	,constructor: function(){		
		this._children = [];
//		this.metadata("childMoveable",true);
//		//console.log(this.declaredClass,"agile._Container:constructor() is called");	
	}
	,init:function(){
		if(this._initContainer){return;}
		this._initContainer = true;
		
//		console.log(this.declaredClass,"[agile._Container] init....");
		if(this.containerNode == null){
			console.error(this.declaredClass,"agile._Container[startup]...containerNode is undefined");
			return;
		}
		this._children = this._lookupChildren();
		this.lastChildIndex = this._children.length + 1;	
//		console.log(this.declaredClass,"this._children.length=",this._children.length);
		array.forEach(this._children,function(child){
			this.initChild(child);
//			child.startup();//20131203
		},this);
				
		
//		aspect.after(this,"addComponent",lang.hitch(this,"onChildAdded"),true);
		
		aspect.after(this,"addComponent",lang.hitch(this,function(child){
//		on(this,"addChild",this,function(child){
			
			this.lastChildIndex++;	
			this._children.push(child);
//			this.sortChildren();
//			//console.log(this.declaredClass,"[agile._Container]:~~addChild:",child);
			child.style1("z-index",++this.childMaxZIndex);
			
			//auto adjust the position for new created child
	 		if(this.autoAdjustChildren){
	 			this.adjustChildOffset(child);
	 		}	 	
	 		//post process for new added child
	 		this.onChildAdded(child);
		}),true);	
		
//		aspect.after(this,"removeChild",lang.hitch(this,"onChildRemoved"),true);	
		aspect.after(this,"removeChild",lang.hitch(this,function(child){
			for(var i = this._children.length - 1; i>= 0; i--){
				if(this._children[i] == child){
					this._children.splice(i,1);
					break;
				}
			} 
			//post process 
			this.onChildRemoved(child);
		}),true);
		
//		aspect.after(this,"onSelected",function(){						
//            array.forEach(this.getSelectedChildren(),function(child){
//                child.onDeselected();
//            });		
//		});
//		
//		this.subscribe("agile.widget.selected",function(selectedWidget){
//			if(!this.isSelected()) return;
//
//			if(selectedWidget == null) return;
////			//console.log("isCtrlKeyActive:",agile.isCtrlKeyActive());
//			//TODO:fix me
//			if(!agile.isCtrlKeyActive()){
//				
//				array.filter(this._children,function(child){return child._selected && child != selectedWidget;}).forEach(function(child){
//					child.onDeselected();						
//				});
//			}
//			////console.log("this.selectedWidgets",this.selectedWidgets);
//		});		
		
		//20141022:
		this.own(
 		on(this.containerNode,"mouseover",lang.hitch(this,function(event){
 			if(agile._selectedIcon){
 				style.set(this.domNode,{cursor:"crosshair"});
 			}else{
 				style.set(this.domNode,{cursor:""});
 			}
 		})) 		
 		,on(this.containerNode,"click",lang.hitch(this,function(event){
 			if(agile._selectedIcon){
// 				console.log(this.declaredClass,"publish...create-widget");
 				topic.publish("create-widget",agile._selectedIcon,event);
 			}
 		}))	
 		);
	}
	,onDataReady:function(){
//		console.log(this.declaredClass,"agile._Container[onDataReady]...1");
//		if(this.hasSelector){
		if(this.agileSelector){
			//this.agileSelector.destroyRecursive();
			construct.place(this.agileSelector,this.getContainerNode(),1);
		}
//		console.log(this.declaredClass,"agile._Container[onDataReady]...2");
		this._children = this._lookupChildren();
		this.lastChildIndex = this._children.length;			
//		this.sortChildren();
//		//console.log(this.declaredClass,"agile._Container[onDownloadEnd]...this._children:",this._children);
//		console.log(this.declaredClass,"agile._Container[onDataReady]...3");C
		array.forEach(this._children,function(child){
			this.initChild(child);
			child.startup();
			var idx = child.style1("z-index");
			if(idx){
				if(this.childMaxZIndex < idx){
					this.childMaxZIndex = idx;
				}	
				child.style1("z-index",idx);
				if(this.childMinZIndex > idx){
					this.childMinZIndex = idx;
				}
			}			
		},this);
//		console.log(this.declaredClass,"agile._Container[onDataReady]...4");
		//
		this.resize();
		
//		console.log(this.declaredClass,"agile._Container[onDataReady]...5");
	}
	[@method "computeSize"/]
	,computeSize:function(){
		//console.log(this.declaredClass,this.id,"[agile._Container]computeSize()");		
		this.computeChildrenSize();
		this.inherited(arguments);
	}
	[@method "computeChildrenSize"/]
	,computeChildrenSize:function(){
		//console.log(this.declaredClass,"[agile._Container]computeChildrenSize()");
		array.forEach(this._children,function(child){
			child.computeSize();
		},this);
	}
	,isSingleSelectMode:function(){
		if(agile.activeKeys[keys.CTRL]){
			return false;
		}
		return this._singleSelect;
	}
	[@method "initChild"/]
	,initChild:function(child){
//		console.log(this.declaredClass,"[agile._Container]initChild",child.declaredClass);
		//child.metadata("anchor",{left:0,top:0});
		child.parent = this;
		//for layout widget
//		if(typeof this.resize == "function"){
//			this.resize();
//		}
		if(typeof child.resize == "function"){
			child.resize();
		}
//		//de-select the container if any of its children is selected
//		if(this.onDeselected){			
//			this.own(aspect.after(child,"onSelected",lang.hitch(this,"onDeselected"),true));
//		}
//		aspect.after(child,"onSelected",lang.hitch(this,function(){
//			console.log("@@@CTRL=",agile.activeKeys[keys.CTRL],"this._singleSelect=",this._singleSelect);
//			if(this._singleSelect && !agile.activeKeys[keys.CTRL]){
//				array.forEach(this.getSelectedChildren(),function(c){
//					if(child != c){
//						c.onDeselected();
//					}
//		        });	
//			}
//		}))	
		//fixme:TODO should the mouse event handlers be moved to child itself(_Component)?
//		this.own(
//				on(child.domNode,"mousedown",lang.hitch(this,function(event){
////					child._onmouseDown = true;
//						if(mouse.isRight(event)){	
//							var offset = {left: event.offsetX,top: event.offsetY};				
//							topic.publish("agile.widget.selectedTarget",child,offset);
//							event.stopPropagation();
//						}
//				}))
				
//				,on(child.domNode,"mousemove",lang.hitch(this,function(event){
//					if(child._onmouseDown){
//						if(!child._selected){					
//							child.onSelected();
//							topic.publish("agile.widget.selected",child);					
//						}	
//						if(!child._cursorMove){
//							style.set(child.domNode,{cursor:"move"});
//							child._cursorMove = true;
//						}
//					}			
//				}))
//				
//				,on(child.domNode,"mouseup",lang.hitch(this,function(event){
//					child._onmouseDown = false;			
//					style.set(child.domNode,{cursor:"default"});
//					child._cursorMove = false;
//				}))
//		);
	    
		//console.log(this.declaredClass,"constrainedMoveable:",this.metadata("constrainedMoveable"),",moveable:",child.metadata("moveable"));
		if(/*this.metadata("childMoveable") && */child.metadata("moveable") && !child.moveableWidget){			
			var moveable = null;
//			if(child.metadata("constrainedMoveable") || this.domNode == this.containerNode){
				//console.log(this.declaredClass,"@@constrainedMoveable......",child.parent.dimension,child.metadata("anchor"));
				moveable = new move.constrainedMoveable(child.domNode,{
					within: true				
					,constraints:function(){							
//						return {
//							l: child.metadata("anchor.left") + 1
//							,t: child.metadata("anchor.top") + 1
//							,w: child.parent.dimension.width - 1
//							,h: child.parent.dimension.height - 1
//						}
						return child.parent.getMovableConstraint();
					}
				});
//			}else{
//				//console.log(this.declaredClass,"@@parentConstrainedMoveable......");
//				moveable = new move.parentConstrainedMoveable(child.domNode,{within: true});
//			}
		
			//20150522:pin widget & allow selection in widget
			child.moveableWidget = moveable;
			
			this.own(
				aspect.after(moveable,"onMoving",lang.hitch(child,function(mover,leftTop){
//					if(!child._isMoving) return;
					var box = agile.calcSize(mover.host.node);
					var anchor = this.metadata("anchor")||{left:0,top:0};	
//					console.log(this.declaredClass,"[onMoving]parent id=",child.parent.id,"box=",box,"anchor=",anchor);
					topic.publish("agile.component.moving." + child.parent.id ,mover.host.node, box.l - anchor.left, box.t - anchor.top);
	//				//console.log(this.declaredClass,"onMoving:",box,leftTop);
					topic.publish("agile.widget.changed.styles",child,"style.left",(box.l - anchor.left)+"px");	
					topic.publish("agile.widget.changed.styles",child,"style.top",(box.t - anchor.top)+"px");
					
				}),true)	
				
				,aspect.after(moveable,"onMoveStart",lang.hitch(child,function(){
//					console.log(this.declaredClass,"[onMoveStart] _selected=",child._selected);
//					child._isMoving = true;
					child.metadata("_boxBeforeMove",agile.calcSize(child.domNode));
					style.set(this.domNode,{cursor:"move"});

//					if(!child._selected){		
//						child.onSelected();
//						topic.publish("agile.widget.selected",child);					
//					}
				}),true)
								
				,aspect.after(moveable,"onMoveStop",lang.hitch(child,function(mover){	
//					child._isMoving = false;
					style.set(this.domNode,{cursor:"default"});
					var boxBeforeMove = child.metadata("_boxBeforeMove");
					var boxAfterMove = agile.calcSize(child.domNode);
//					console.log(this.declaredClass,"[onMoveStop]","boxBeforeMove:",boxBeforeMove,"boxAfterMove:",boxAfterMove);
					if(boxBeforeMove && boxAfterMove){
						if(boxBeforeMove.l != boxAfterMove.l || boxBeforeMove.t != boxAfterMove.t){
							child.metadata("style.left",boxAfterMove.l);
							child.metadata("style.top",boxAfterMove.t);
							if(child["onMoveStop"]){						
								child.onMoveStop({left:boxAfterMove.l,top:boxAfterMove.t});
							}
							
						   var operations = []
						   if(boxBeforeMove.l != boxAfterMove.l){
							   operations.push({action:"update",target:this,category:"style",property:"left",beforeValue:boxBeforeMove.l + "px",afterValue:boxAfterMove.l +"px"});
						   }
						   if(boxBeforeMove.t != boxAfterMove.t){
							   operations.push({action:"update",target:this,category:"style",property:"top",beforeValue:boxBeforeMove.t +"px",afterValue:boxAfterMove.t + "px"});
						   }
						   if(operations.length > 0){
							   agile.commit(operations);
						   }
						}
					}					
				}),true)
			);
			
		}
	}
    [@method "addComponent"/]
	,addComponent:function(child,offset){		
		////console.log("[agile._Container]","Adding " + child.declaredClass + " to " + this.declaredClass);
		////console.log("child.domNode",child.domNode,"this.getContainerNode()",this.getContainerNode());
//		construct.place(child.domNode,this.getContainerNode(),"last");		
		if(offset && offset.insertIndex != undefined){
			this.addChild(child,offset.insertIndex);
		}else if(child.insertIndex != undefined){//for undo operation
			this.addChild(child,child.insertIndex);
		}		
		else{
			this.addChild(child,"last");
			//child.insertIndex = this.lastChildIndex;
		}
		//child.parentContainerNode = this.getContainerNode();
		child.parent = this;
		//child.metadata("anchor",{left:0,top:0});
		child.metadata("anchor",this.metadata("anchor"));
		//child.updateZindex();
		this.initChild(child);
				
//		console.log(this.declaredClass,"addComponent:offset",offset,"anchor",child.metadata("anchor"));
		if(offset){
			if(this.sortAxis == "x" && offset.left != undefined){			
				
				child.metadata("style.left",offset.left);
				style.set(child.domNode,{left:offset.left +"px"});
			}else if(this.sortAxis == "y" && offset.top != undefined){
//				child.metadata("style.left",1);
				child.metadata("style.top",offset.top);			
//				style.set(child.domNode,{left:1,top:offset.top});
				style.set(child.domNode,{top:offset.top +"px"});
			}else{
				if(offset.left != undefined){
					child.metadata("style.left",offset.left);
					style.set(child.domNode,{left:offset.left +"px"});
				}
				if(offset.top != undefined){	
					child.metadata("style.top",offset.top);
					style.set(child.domNode,{top:offset.top +"px"});
				}
			}
		}
	}
	,selectChild:function(child){
		
	}
	[@method "removeSelectedChildren"/]
	,removeSelectedChildren:function(){	
		for(var i = this._children.length - 1; i >= 0; i--){	
			if(this._children[i]._selected){
				this.removeChild(this._children[i]);
			}
		}
	}
	[@method "sortChildren"/]
	,sortChildren:function(){
		if(this.sortAxis == "x"){
			this._children = this._children.sort(function(child1,child2){
				////console.log(child1.metadata("parameters.header")+".left",child1.metadata("style.left"),child2.metadata("parameters.header")+".left",child2.metadata("style.left"));
//				//console.log("child1=",child1,",child2=",child2);
				if(child1.dimension.left > child2.dimension.left){
					return 1;
				}else if(child1.dimension.left  < child2.dimension.left ){
					return -1;
				}else{
					return 0;
				}
			});
		}else if(this.sortAxis == "y"){
			this._children = this._children.sort(function(child1,child2){
				if(child1.dimension.top > child2.dimension.top ){
					return 1;
				}else if(child1.dimension.top < child2.dimension.top ){
					return -1;
				}else{
					return 0;
				}
			});
		}
		return this._children;
	}
	,_lookupChildren:function(){
		var _children = [];
		query(">.agileComponent",this.getContainerNode()).forEach(function(node,idx){
			_children.push(registry.byNode(node));						
		},this);
		return _children;
	}
	,getContainerNode:function(){
		if(this.containerNode == null){
			console.error(this.declaredClass,"containerNode undefined");
		}
		return this.containerNode;
	}
	,isSelected:function(){
		//return domClass.contains(this.domNode,"agileSelected");
		return this._selected;
	}
	,onChildAdded:function(child){		
//		console.log(this.declaredClass,"[agile._Container] onChildAdded",child);		
	}	
	,onChildRemoved:function(child){		
//		console.log(this.declaredClass,"[agile._Container] @@onChildRemoved",child);
	}
	,onChildSelected:function(child){
//		//console.log(this.declaredClass,"[agile._Container] onChildSelected",child);		
		child._selected = true;
		this.selectedChild = child;
	}
	,_getChildren:function(){		
		return this._children;
	}
	,getSelectedChildren:function(){
//		//console.log(this.declaredClass,"[agile._Container] getSelectedChildren",this._children);
		return array.filter(this._children,function(child){return child._selected});
//		return this.selectedWidgets;
	}	
//	,toPrototype:function(mimeType){//move to MockupEditPage
//		var prototype = ""
////		//console.log(this.declaredClass,"[agile._Container] toPrototype:",mimeType,this._children.length);	
//		array.forEach(this._children,function(child){
//			prototype += child.toHtml(true,0,mimeType);
//		});
//		return prototype;
//	}	
	,adjustChildOffset:function(child){		
		var children = this.getChildren();		
		
		if(this.sortAxis == "y"){		
			var maxTop = 0;
			var top = 0;
			var childx = null;
			for(var i = children.length - 1; i >= 0; i--){
				top = children[i].dimension.top;
				if(!isNaN(top) && maxTop < top){
					maxTop = top;
					childx = children[i];
				}
			}
			child.metadata("style.top",maxTop == 0? 10 : maxTop + childx.getPreferredSize().h);
			style.set(child.domNode,"top",child.metadata("style.top"));
			
		}else if(this.sortAxis == "x"){			
			var maxLeft = 0;
			var left = 0;
			var childx = null;
			for(var i = children.length - 1; i >= 0; i--){
				//left = children[i].metadata("style.left");
				left = children[i].dimension.left;
				if(!isNaN(left) && maxLeft < left){
					maxLeft = left;
					childx = children[i];
				}
			}
			child.metadata("style.left",maxLeft == 0? 10 : maxLeft + childx.getPreferredSize().w);
			style.set(child.domNode,"left",child.metadata("style.left"));			
		}			
	}
	,getMovableConstraint:function(){									
		return {
			l: 1
			,t: 1
			,w: this.dimension.width - 1
			,h: this.dimension.height - 1
		}		
	}
[/@]
